package com.gitee.wsl.doc.prosemirror.plugin.parser

import com.gitee.wsl.doc.prosemirror.model.attr.Attrs

/**
 * 用于指定Markdown令牌如何解析的对象类型
 */
interface ParseSpec<Token> {
    /**
     * 此令牌映射到单个节点，其类型可以在模式中按给定名称查找。
     * 必须设置`node`、`block`或`mark`中的一个
     */
    val node: String?

    /**
     * 此令牌（除非`noCloseToken`为true）具有`_open`和`_close`变体，
     * 并包装一个内容块。该块应包装在由属性值命名的类型的节点中。
     * 如果令牌没有`_open`或`_close`，请使用`noCloseToken`选项。
     */
    val block: String?

    /**
     * 此令牌（同样，除非`noCloseToken`为true）也具有`_open`和`_close`变体，
     * 但应该向其内容添加标记（由值命名），而不是将其包装在节点中。
     */
    val mark: String?

    /**
     * 节点或标记的属性。当提供`getAttrs`时，它优先。
     */
    val attrs: Attrs?

    /**
     * 用于计算节点或标记属性的函数，
     * 接受一个markdown-it令牌并返回属性对象。
     */
    val getAttrs: ((token: Token, tokenStream: List<Token>, index: Int) -> Attrs?)?

    /**
     * 指示[markdown-it令牌]没有节点的`_open`或`_close`。
     * 对于`code_inline`、`code_block`和`fence`，默认为`true`。
     */
    val noCloseToken: Boolean?

    /**
     * 当为true时，忽略匹配令牌的内容。
     */
    val ignore: Boolean?
}

/**
 * 解析规范的实现类
 */
data class ParseSpecImpl<Token>(
    override val node: String? = null,
    override val block: String? = null,
    override val mark: String? = null,
    override val attrs: Attrs? = null,
    override val getAttrs: ((token: Token, tokenStream: List<Token>, index: Int) -> Attrs?)? = null,
    override val noCloseToken: Boolean? = null,
    override val ignore: Boolean? = null
) : ParseSpec<Token> {

    init {
        // 验证必须设置node、block或mark中的一个
        val count = listOf(node, block, mark).count { it != null }
        require(count == 1) { "Exactly one of 'node', 'block', or 'mark' must be set" }
    }
}